#!/usr/bin/python
# -*- coding: utf-8 -*-
# @Version        : 1.0
# @Update Time    : 2025/8/26 12:00
# @File           : upload.py
# @IDE            : PyCharm
# @Desc           : 文件上传相关的FastAPI路由接口

from typing import List, Optional

from fastapi import APIRouter, UploadFile, File, Form, HTTPException, Query
from pydantic import BaseModel, Field

from applications.core.exceptions import BaseAppException
from applications.utils.http import success_api, fail_api
from applications.utils.upload_file.file_factory import FileUploadFactory
from applications.utils.upload_file.file_utils import FileUtils

router = APIRouter(prefix="/upload", tags=["文件上传"])


# 响应模型
class FileTypeResponse(BaseModel):
    """文件类型检测响应"""

    filename: str = Field(..., description="文件名")
    extension: str = Field(..., description="文件扩展名")
    file_type: str = Field(..., description="文件类型")
    mime_type: str = Field(..., description="MIME类型")
    size: int = Field(..., description="文件大小(字节)")
    size_human: str = Field(..., description="可读文件大小")


class UploadResponse(BaseModel):
    """文件上传响应"""

    success: bool = Field(..., description="上传是否成功")
    file_path: Optional[str] = Field(None, description="文件路径")
    url: Optional[str] = Field(None, description="文件访问URL")
    thumbnail_url: Optional[str] = Field(None, description="缩略图URL")
    file_info: Optional[dict] = Field(None, description="文件详细信息")
    message: str = Field("", description="响应消息")


class BatchUploadResponse(BaseModel):
    """批量上传响应"""

    total: int = Field(..., description="总文件数")
    success_count: int = Field(..., description="成功上传数")
    failed_count: int = Field(..., description="失败上传数")
    results: List[UploadResponse] = Field(..., description="详细结果")


class FileInfoResponse(BaseModel):
    """文件信息响应"""

    exists: bool = Field(..., description="文件是否存在")
    file_info: Optional[dict] = Field(None, description="文件信息")
    url: Optional[str] = Field(None, description="文件访问URL")


@router.post("/detect-type", response_model=FileTypeResponse, summary="检测文件类型")
async def detect_file_type(file: UploadFile = File(..., description="要检测的文件")):
    """
    检测上传文件的类型和基本信息

    - **file**: 上传的文件
    - **返回**: 文件类型、MIME类型、大小等信息
    """
    try:
        # 验证文件
        file_info = await FileUtils.validate_upload_file(
            file=file,
            max_size=100,  # 检测用，设置较大的限制
            allowed_extensions=None,  # 不限制类型
            allowed_mime_types=None,
        )

        # 获取文件类型
        file_type = FileUtils.get_file_type_by_extension(file.filename or "")

        return FileTypeResponse(
            filename=file.filename or "",
            extension=file_info.get("extension", ""),
            file_type=file_type,
            mime_type=file.content_type or "",
            size=file.size or 0,
            size_human=FileUtils.format_file_size(file.size or 0),
        )
    except BaseAppException as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"检测文件类型失败: {str(e)}")


@router.post("/single", response_model=UploadResponse, summary="单文件上传")
async def upload_single_file(
    file: UploadFile = File(..., description="要上传的文件"),
    path: str = Form("uploads", description="保存路径"),
    upload_type: str = Form("local", description="上传类型: local, qiniu"),
    file_type: str = Form("auto", description="文件类型: auto, image, video, audio, file"),
    max_size: int = Form(10, description="最大文件大小(MB)"),
    create_thumbnail: bool = Form(False, description="是否创建缩略图（仅图片）"),
    compress_image: bool = Form(False, description="是否压缩图片"),
):
    """
    单个文件上传

    - **file**: 上传的文件
    - **path**: 保存路径，默认为 "uploads"
    - **upload_type**: 上传类型，支持 "local"（本地）和 "qiniu"（七牛云）
    - **file_type**: 文件类型，"auto"自动检测，或指定 "image", "video", "audio", "file"
    - **max_size**: 最大文件大小限制(MB)
    - **create_thumbnail**: 是否为图片创建缩略图
    - **compress_image**: 是否压缩图片
    """
    try:
        # 验证上传类型
        if not FileUploadFactory.validate_upload_type(upload_type):
            raise HTTPException(status_code=400, detail=f"不支持的上传类型: {upload_type}")

        # 自动检测文件类型
        if file_type == "auto":
            detected_type = FileUtils.get_file_type_by_extension(file.filename or "")
            file_type = detected_type if detected_type in ["image", "video", "audio"] else "file"

        # 上传文件并获取详细结果
        result = await FileUploadFactory.upload_with_result(
            path=path,
            file=file,
            upload_type=upload_type,
            file_type=file_type,
            max_size=max_size,
            create_thumbnail=create_thumbnail and file_type == "image",
        )

        # 如果是图片且需要压缩
        if compress_image and file_type == "image" and result.success:
            try:
                FileUtils.compress_image(result.file_path, quality=85, max_width=1920, max_height=1080)
            except Exception:
                pass  # 压缩失败不影响上传结果

        return UploadResponse(
            success=result.success,
            file_path=result.file_path,
            url=result.url,
            thumbnail_url=result.thumbnail_path,
            file_info=result.file_info,
            message=result.message or ("上传成功" if result.success else "上传失败"),
        )

    except BaseAppException as e:
        return UploadResponse(success=False, message=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"上传失败: {str(e)}")


@router.post("/batch", response_model=BatchUploadResponse, summary="批量文件上传")
async def upload_multiple_files(
    files: List[UploadFile] = File(..., description="要上传的文件列表"),
    path: str = Form("uploads", description="保存路径"),
    upload_type: str = Form("local", description="上传类型"),
    max_size: int = Form(10, description="最大文件大小(MB)"),
    auto_create_thumbnail: bool = Form(True, description="自动为图片创建缩略图"),
):
    """
    批量文件上传

    - **files**: 上传的文件列表
    - **path**: 保存路径
    - **upload_type**: 上传类型
    - **max_size**: 最大文件大小限制(MB)
    - **auto_create_thumbnail**: 是否自动为图片创建缩略图
    """
    try:
        # 验证上传类型
        if not FileUploadFactory.validate_upload_type(upload_type):
            raise HTTPException(status_code=400, detail=f"不支持的上传类型: {upload_type}")

        results = []

        for file in files:
            try:
                # 自动检测文件类型
                detected_type = FileUtils.get_file_type_by_extension(file.filename or "")
                file_type = detected_type if detected_type in ["image", "video", "audio"] else "file"

                # 上传文件
                result = await FileUploadFactory.upload_with_result(
                    path=path,
                    file=file,
                    upload_type=upload_type,
                    file_type=file_type,
                    max_size=max_size,
                    create_thumbnail=auto_create_thumbnail and file_type == "image",
                )

                results.append(
                    UploadResponse(
                        success=result.success,
                        file_path=result.file_path,
                        url=result.url,
                        thumbnail_url=result.thumbnail_path,
                        file_info=result.file_info,
                        message=result.message or ("上传成功" if result.success else "上传失败"),
                    )
                )

            except Exception as e:
                results.append(UploadResponse(success=False, message=f"文件 {file.filename} 上传失败: {str(e)}"))

        success_count = sum(1 for r in results if r.success)

        return BatchUploadResponse(
            total=len(results), success_count=success_count, failed_count=len(results) - success_count, results=results
        )

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"批量上传失败: {str(e)}")


@router.post("/image", response_model=UploadResponse, summary="图片上传（专用）")
async def upload_image(
    file: UploadFile = File(..., description="图片文件"),
    path: str = Form("images", description="保存路径"),
    upload_type: str = Form("local", description="上传类型"),
    max_size: int = Form(5, description="最大文件大小(MB)"),
    create_thumbnail: bool = Form(True, description="创建缩略图"),
    compress: bool = Form(True, description="压缩图片"),
    thumbnail_size: str = Form("200x200", description="缩略图尺寸，格式: 宽x高"),
):
    """
    专用的图片上传接口，自动处理图片压缩和缩略图生成

    - **file**: 图片文件
    - **path**: 保存路径
    - **upload_type**: 上传类型
    - **max_size**: 最大文件大小(MB)
    - **create_thumbnail**: 是否创建缩略图
    - **compress**: 是否压缩图片
    - **thumbnail_size**: 缩略图尺寸
    """
    try:
        # 验证是否为图片
        if not file.content_type or not file.content_type.startswith("image/"):
            raise HTTPException(status_code=400, detail="只能上传图片文件")

        # 上传图片
        result = await FileUploadFactory.upload_with_result(
            path=path,
            file=file,
            upload_type=upload_type,
            file_type="image",
            max_size=max_size,
            create_thumbnail=create_thumbnail,
        )

        if not result.success:
            return UploadResponse(success=False, message=result.error or "上传失败")

        # 压缩图片
        if compress:
            try:
                FileUtils.compress_image(result.file_path, quality=85, max_width=1920, max_height=1080)
            except Exception as e:
                # 压缩失败不影响上传结果，但记录到消息中
                result.message += f"（图片压缩失败: {str(e)}）"

        return UploadResponse(
            success=True,
            file_path=result.file_path,
            url=result.url,
            thumbnail_url=result.thumbnail_path,
            file_info=result.file_info,
            message=result.message or "图片上传成功",
        )

    except BaseAppException as e:
        return UploadResponse(success=False, message=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"图片上传失败: {str(e)}")


@router.get("/info", response_model=FileInfoResponse, summary="获取文件信息")
async def get_file_info(
    file_path: str = Query(..., description="文件路径"), upload_type: str = Query("local", description="上传类型")
):
    """
    获取文件详细信息

    - **file_path**: 文件路径
    - **upload_type**: 上传类型
    """
    try:
        # 检查文件是否存在
        exists = await FileUploadFactory.file_exists(file_path, upload_type)

        if not exists:
            return FileInfoResponse(exists=False, file_info=None, url=None)

        # 获取文件信息
        file_info = await FileUploadFactory.get_file_info(file_path, upload_type)
        file_url = await FileUploadFactory.get_file_url(file_path, upload_type)

        return FileInfoResponse(exists=True, file_info=file_info, url=file_url)

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取文件信息失败: {str(e)}")


@router.delete("/delete", summary="删除文件")
async def delete_file(
    file_path: str = Query(..., description="文件路径"), upload_type: str = Query("local", description="上传类型")
):
    """
    删除指定文件

    - **file_path**: 文件路径
    - **upload_type**: 上传类型
    """
    try:
        success = await FileUploadFactory.delete_file(file_path, upload_type)

        return success_api(data={"deleted": success}, msg="删除成功" if success else "文件不存在或删除失败")

    except Exception as e:
        return fail_api(msg=f"删除文件失败: {str(e)}")


@router.get("/strategies", summary="获取可用的上传策略")
async def get_upload_strategies():
    """
    获取所有可用的上传策略及其配置信息
    """
    try:
        strategies = FileUploadFactory.get_available_strategies()
        strategy_info = {}

        for strategy in strategies:
            try:
                info = FileUploadFactory.get_strategy_info(strategy)
                strategy_info[strategy] = info
            except Exception as e:
                strategy_info[strategy] = {"error": str(e)}

        return success_api(
            data={
                "available_strategies": strategies,
                "default_strategy": FileUploadFactory.get_default_upload_type(),
                "strategy_details": strategy_info,
            },
            msg="获取策略信息成功",
        )

    except Exception as e:
        return fail_api(msg=f"获取策略信息失败: {str(e)}")


@router.post("/validate", summary="验证文件")
async def validate_file(
    file: UploadFile = File(..., description="要验证的文件"),
    max_size: int = Form(10, description="最大文件大小(MB)"),
    allowed_extensions: Optional[str] = Form(None, description="允许的扩展名，逗号分隔"),
    allowed_mime_types: Optional[str] = Form(None, description="允许的MIME类型，逗号分隔"),
):
    """
    验证文件是否符合要求

    - **file**: 要验证的文件
    - **max_size**: 最大文件大小(MB)
    - **allowed_extensions**: 允许的扩展名，如: ".jpg,.png,.gif"
    - **allowed_mime_types**: 允许的MIME类型，如: "image/jpeg,image/png"
    """
    try:
        # 处理参数
        extensions = None
        if allowed_extensions:
            extensions = [ext.strip() for ext in allowed_extensions.split(",")]

        mime_types = None
        if allowed_mime_types:
            mime_types = [mime.strip() for mime in allowed_mime_types.split(",")]

        # 验证文件
        file_info = await FileUtils.validate_upload_file(
            file=file, max_size=max_size, allowed_extensions=extensions, allowed_mime_types=mime_types
        )

        return success_api(data={"valid": True, "file_info": file_info, "message": "文件验证通过"}, msg="验证成功")

    except BaseAppException as e:
        return success_api(data={"valid": False, "error": str(e), "message": "文件验证失败"}, msg="验证完成")
    except Exception as e:
        return fail_api(msg=f"验证失败: {str(e)}")
